#include<iostream>
#include<unistd.h>
#include<string>
#include <sys/types.h>              ////
#include <sys/socket.h>             ////
#include<netinet/in.h>//            ////
#include<arpa/inet.h>//这两个是      ////这四个头文件是套接字的固定头文件
#include<cstring>
#include"nocopy.hpp"
#include"Log.hpp"
#include"InetAddr.hpp"
using namespace log_ns;
//服务端
static const int gsockfd=-1;
static const uint16_t glocalport=8888;
enum{
    SOCKET_ERROR=1,
    BIND_ERROR
};
class UdpServer :public nocopy
{
public:
    //=glocalport
    UdpServer(uint16_t localport = glocalport):_sockfd(gsockfd),
                                                            _localport(localport),
                                                            _isrunning(false)
    {

    }
    void InitServer()
    {
        //创建套接字
        _sockfd=::socket(AF_INET,SOCK_DGRAM,0);//这里直接设置为零就可以了会自定选择协议
        if(_sockfd<0)
        {
            LOG(FATAL,"socket error\n");
            exit(SOCKET_ERROR);//直接退出

        }
        LOG(DEBUG,"socket create success, _sockfd:%d \n",_sockfd);
        //创建结构体//这个结构体就是一个空间用来存放套接字的ip和端口
        //这是一个类型上面是他头文件//报文中包括自己的端口号和目标的端口号；
    
        struct sockaddr_in local;//sockaddr结构
        memset(&local,0,sizeof(local));
        local.sin_family=AF_INET;
        local.sin_port=htons(_localport);
        // local.sin_addr.s_addr=inet_addr("172.0.0.1");//网络通讯需要四字节ip2需要转网络序列
         local.sin_addr.s_addr=INADDR_ANY;//就是0任一ip绑定
        //2.bind（关联接口）//这里就是将结构体和套接字关联起来
        int n=::bind(_sockfd,(struct sockaddr *)&local,sizeof(local));
        if(n<0)
        {
            LOG(FATAL,"bind erro\n");
            exit(SOCKET_ERROR);//直接退出
        }
        LOG(DEBUG,"socket bind  success\n");
    }
    //     void InitServer()
    // {
    //     // 1. 创建socket文件
    //     _sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);
    //     if (_sockfd < 0)
    //     {
    //         LOG(FATAL, "socket error\n");
    //         exit(SOCKET_ERROR);
    //     }
    //     LOG(DEBUG, "socket create success, _sockfd: %d\n", _sockfd); // 3

    //     // 2. bind
    //     struct sockaddr_in local;
    //     memset(&local, 0, sizeof(local));
    //     local.sin_family = AF_INET;
    //     local.sin_port = htons(_localport);
    //     // local.sin_addr.s_addr = inet_addr(_localip.c_str()); // 1. 需要4字节IP 2. 需要网络序列的IP -- 暂时
    //     local.sin_addr.s_addr = INADDR_ANY; // 服务器端，进行任意IP地址绑定

    //     int n = ::bind(_sockfd, (struct sockaddr *)&local, sizeof(local));
    //     if (n < 0)
    //     {
    //         LOG(FATAL, "bind error\n");
    //         exit(BIND_ERROR);
    //     }
    //     LOG(DEBUG, "socket bind success\n");
    // }
    void Start ()
    {
        
        _isrunning=true;
        char inbuffer[1024];
        while (_isrunning)
        {
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            //接收
            ssize_t n=recvfrom(_sockfd,inbuffer,sizeof(inbuffer)-1,0,(struct sockaddr*)&peer,&len);//这里的peer是用来接受发送方消息的
// 这个函数是为了接受数据的函数，  上面创建的文件  缓冲区             这里的0表示非阻塞       发送方信息
            std::cout<<"liu"<<std::endl;
            if(n>0)
            {
                //处理
                InetAddr addr(peer);
                inbuffer[n]=0;
                std::cout<<"client say#"<<inbuffer<<std::endl;//没有发送方信息的版本
                std::cout<<"["<<addr.Ip()<<":"<<addr.Port()<<"]#"<<inbuffer<<std::endl;//包含发送方消息的输出
                std::string echo_string="[udp_server echo] #";
                echo_string +=inbuffer;

                //发送
                sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,(struct sockaddr *)&peer,len);

            }
            else
            {
                std::cout<<"erro"<<std::endl;
            }
        }

    }
    ~UdpServer()
    {
        if(_sockfd>gsockfd) ::close(_sockfd);
    }
private:
     int _sockfd;//套接字
    uint16_t _localport;//端口号
    //服务段没有IP可以直接设置位0
    bool _isrunning;
};
